﻿using System;
using Needle.Utils.Collections;

namespace Needle.Bus.Engine.Stages
{
    public class StageCollection : KeyedCollection<string,IStage> 
    {

        #region constructor

        public StageCollection()
            : base(stage => stage.Id)
        { }

        #endregion

        protected override void ClearItems()
        {
            foreach (var stage in this)
                DetachEvents(stage);
            base.ClearItems();
        }

        protected override void InsertItem(int index, IStage item)
        {
            ValidateItem(item);
            AttachEvents(item);
            base.InsertItem(index, item);
        }

        protected override void SetItem(int index, IStage item)
        {
            ValidateItem(item);
            DetachEvents(this[index]);
            AttachEvents(item);
            base.SetItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            DetachEvents(this[index]);
            base.RemoveItem(index);
        }
   
        private void ValidateItem(IStage item)
        {
            if (item == null)
                throw new ArgumentNullException("item", "item is null.");
            if (Contains(item) || Contains(item.Id))
                throw new ArgumentException("stage, or stage with same id already added");
        }

        #region events

        public event EventHandler StageOpening;
        private void OnStageOpening(object sender, EventArgs e)
        {
            EventHandler handler = StageOpening;
            if (handler != null)
                handler(sender, e);
        }
        public event EventHandler StageOpened;
        private void OnStageOpened(object sender, EventArgs e)
        {
            EventHandler handler = StageOpened;
            if (handler != null)
                handler(sender, e);
        }
        public event EventHandler StageClosing;
        private void OnStageClosing(object sender, EventArgs e)
        {
            EventHandler handler = StageClosing;
            if (handler != null)
                handler(sender, e);
        }
        public event EventHandler StageClosed;
        private void OnStageClosed(object sender, EventArgs e)
        {
            EventHandler handler = StageClosed;
            if (handler != null)
                handler(sender, e);
        }

        public event EventHandler StageFaulted;
        private void OnStageFaulted(object sender, EventArgs e)
        {
            EventHandler handler = StageFaulted;
            if (handler != null)
                handler(sender, e);
        }

        private void AttachEvents(IStage stage)
        {
            stage.Opening += OnStageOpening;
            stage.Opened += OnStageOpened;
            stage.Closing += OnStageClosing;
            stage.Closed += OnStageClosed;
            stage.Faulted += OnStageFaulted;
        }

        private void DetachEvents(IStage stage)
        {
            stage.Opening -= OnStageOpening;
            stage.Opened -= OnStageOpened;
            stage.Closing -= OnStageClosing;
            stage.Closed -= OnStageClosed;
            stage.Faulted -= OnStageFaulted;
        }

        #endregion

    }
}
